package com.redstar.interesting.common.starter.config;

import com.redstar.interesting.common.util.ThreadMDCUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.common.utils.NamedThreadFactory;
import org.slf4j.MDC;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.concurrent.*;

/**
 * @author lihongxing
 */
@Slf4j
@Configuration
public class ThreadPoolConfigurer {


    @Bean("threadPoolExecutor")
    public ThreadPoolExecutor getThreadPoolExecutor() {
        return new ThreadPoolExecutor(5,
                10,
                0,
                TimeUnit.SECONDS,
                new LinkedBlockingDeque<>(1000),
                new NamedThreadFactory("threadPoolExecutor"),
                new ThreadPoolExecutor.AbortPolicy()) {
            @Override
            public void execute(Runnable command) {
                super.execute(ThreadMDCUtil.wrap(command, MDC.getCopyOfContextMap()));
            }

            @Override
            public <T> Future<T> submit(Callable<T> task){
                return super.submit(ThreadMDCUtil.wrap(task, MDC.getCopyOfContextMap()));
            }

            @Override
            public Future<?> submit(Runnable task) {
                return super.submit(ThreadMDCUtil.wrap(task, MDC.getCopyOfContextMap()));
            }

            @Override
            public <T> Future<T> submit(Runnable task, T result){
                return super.submit(ThreadMDCUtil.wrap(task, MDC.getCopyOfContextMap()), result);
            }

            @Override
            protected void afterExecute(Runnable runnable, Throwable throwable) {
                super.afterExecute(runnable, throwable);
                if (runnable instanceof Future<?> && null == throwable) {
                    Future<?> future = (Future<?>) runnable;
                    if (future.isDone()) {
                        try {
                            future.get();
                        } catch (InterruptedException | ExecutionException e) {
                            log.error("threadPoolExecutorError", e);
                        }
                    }
                }
                if (null != throwable) {
                    log.error("threadPoolExecutor execute error, message:{},{}", throwable.getMessage(), throwable);
                }
            }
        };
    }


}
